<template>
  <div>
    <!--
        dialog组件(内给相应标签 / 按键-绑定了事件和一些代码)
        组件关闭方式↓
        1 点击遮罩层上,会导致弹窗关闭
        2 按下esc键。会导致弹窗关闭
        3 点击右上角的 x 按钮,会导致弹窗关闭
        4 点击确认和取消,可以自己写弹窗关闭

        问题: 为何dialog组件内不直接修改visivle这个props变量,而是要传递出来给 dialogVisible变量赋值?
              然后再流回到visible影响组件显示/隐藏?
        知识点: props变量是只读的,不能直接赋值(vue会警告)
        原因: Vue设计上, 父组件如果重新渲染,会给props里变量重新赋值,你原来在子组件内给props赋予的值将会被覆盖掉丢失
        解决:
             1 用data/computed代替(后面老师会讲)
             2 快速改变父范围data的变量(双向绑定) -> 让父组件把值改完再流回给 props 影响组件内(单向数据流)
             单向数据流: 尽量让父组件改变值,重新给props赋值 (父 > 子)



      关闭 dialog 是改变 visible 对应的变量为 false 内部检测 visible 属性值为 false,才隐藏dialog 标签的
      使用到的技术: 子 > 父 组件通信 , 改变父组件 visible 的值
      以前的技术 : 子 $emit('自定义事件名',传递给父组件的值)
                   父 子组件标签绑定自定义事件函数,在声明函数时用形参接收子组件传递过来的值

       .sync 语法糖: 本质上还是用的上面的技术,但是语法上简化了很多
       1 子组件内恰当的时机, $emit('update:PropsValue变量名',值)
       2 父组件内,给子组件对应props变量名.sync="父组件范围内data里面的变量"

       .sync作用: 它会在运行时,给当前绑定自定义事件名和事件处理函数
       1 :visible="dialogVisible"
       2 @update:visible="val => dialogvisible = val"

      .sync场景: 子 > 父 快速传值并赋予给父范围内 data 里的变量
                如果子 > 父 要执行逻辑代码很多,这个.sync不能用了,还要我们自己绑定事件
     -->
    <!--
     问题: visible不能使用 .sync语法糖,因为这样就会触发内部自定义 update 事件,
            这样就等于间接把 props 的值改了
     解决: 这里需要手动绑定 update 自定义事件(手动 .sync),
            提交自定义事件给父组件即可 函数 $emit('update:departmentDialog',false)

            @update:visible="(false) => $emit('update:departmentDialog',false)
            这里的 @update:visible 有点想不明白,这不是子组件写的玩意吗?父组件怎么也绑定了该事件
            后面的函数中接收的形参false还没用到,但是值是value
            当然也可以把点击蒙层关闭的功能给关掉只留下确定取消按钮的功能
     -->
    <el-dialog
    :title="isEdit ? '编辑部门':'添加部门'"
    :visible="departmentDialog"
    width="50%"
    :close-on-press-escape="false"
    :show-close="false"
    @update:visible="(val) => $emit('update:departmentDialog',true)"
    @closed="dialogCloseFn"
    >
      <!-- 表单对象 -->
      <template>
        <el-form ref="deptForm" :model="form" :rules="rules" label-width="120px">
          <el-form-item label="部门名称" prop="name">
            <el-input v-model="form.name" style="width:80%" placeholder="1-50个字符" />
          </el-form-item>
          <el-form-item label="部门编码" prop="code">
            <el-input v-model="form.code" style="width:80%" placeholder="1-50个字符" />
          </el-form-item>
          <el-form-item label="部门负责人" prop="manager">
            <el-select v-model="form.manager" style="width:80%" placeholder="请选择">
              <el-option v-for="item in staffList" :key="item.id" :value="item.username" />
            </el-select>
          </el-form-item>
          <el-form-item label="部门介绍" prop="introduce">
            <el-input v-model="form.introduce" style="width:80%" placeholder="1-300个字符" type="textarea" :rows="3" />
          </el-form-item>
        </el-form>
      </template>
      <span slot="footer" class="dialog-footer">
        <el-button @click="cancelFN">取 消</el-button>
        <el-button type="primary" @click="confirmFN">确 定</el-button>
      </span>
    </el-dialog>
  </div>
</template>
<script>
  export default {
    props: {
      // 接收父组件传递过来的弹出层值
      departmentDialog: {
        type: Boolean
      },
      staffList: {
        type: Array,
        default: () => []
        // default: () => ({}) 返回对象的写法,为什么需要()扩着对象?
      },
      // 校验部门code / 部门名称 是否重复
      originList: {
        type: Array,
        default: () => []
      },
      // 编辑状态下校验部门编码
      isEdit: {
        type: Boolean,
        default: false
      },
      // 选中当前的对象部门架构的id(编辑筛选用)
      selectedPid: {
        type: String,
        default: ''
      },
    },
    name: 'DialogIndex',
    data() {
        // 自定义校验规则(部门编号)
        const validCode = (rule,value,callback) => {
          // 新增部门: code部门编码,不能和所有人相同
        let codeList = this.originList.map(item => item.code) // 把 item.code 单独整合成一个数组
        /*
          编辑部门:
          问题: 自己编码和自己冲突了,正确效果是,编辑时,自己的部门编码可以直接用
          原因: codeList的code数组里包含编辑对象本身,value和所有部门进行对比了
          解决: 把自己从所有人里淘汰出去,留下剩下(过滤filter方法)
                然后再把过滤后的数组进行map重组筛选出code
        */
        if(this.isEdit){
          // 排除自己,不和自己比
          // selectedPid一定是有值的,值是当前(父/子)对象的id
          let newArr = this.originList.filter(item => item.id !== this.selectedPid)
          // 重组,不重组得到的是数组对象
          codeList = newArr.map(item => item.code)
        }
        codeList.includes(value) ? callback(new Error(`该${value}值已存在请更换其他部门编码`)): callback() // 放行
      }
      // 校验部门名称是否重复，不能和同级重复
      const validDepartmentName = (rule,value,callback) => {
        // 新增部门名字: (先找到同级部门名称)
        // 数据规律: 子部门pid = 父部门id
        // 添加一级的时候传进来的 selectedPid = '' 只会筛选出一级的
        // 添加二级的时候传进来的 selectedPid = 一级父id 只会筛选出当前父的儿子,因为子pid = 父id
        let filterArr = this.originList.filter(item => item.pid === this.selectedPid)
        let validname = filterArr.map(item => item.name)

        if(this.isEdit){
          // 筛选当前所点击的编辑对象
          // selectedPid一定是有值的,值是当前(父/子)对象的id
          const obj = this.originList.find(item => item.id === this.selectedPid) // 找到自己
          // 一级时 pid = ''
          // 二级是 pid = 父的id  子pid = 父id
          let pid = obj.pid // 拿到编辑对象的pid
          // 筛选出 一级 一组,二级 一组,…………
          // selectedPid一定是有值的,值是当前(父/子)对象的id
          filterArr = this.originList.filter(item => item.pid == pid && item.id !== this.selectedPid)
          // console.log(filterArr,'tongji')
          // 排除自己,对 validname 数组重新赋值 ['人事','技术','财务',……]
          validname = filterArr.map(item => item.name)
        }

        validname.includes(value) ? callback(new Error(`该部门下该${value}名称已经存在`)) : callback()
      }
      return {
        // dialogVisible: false,
        form: {
          name: '', // 部门名称
          code: '', // 部门编码
          manager: '', // 部门管理者
          introduce: '' // 部门介绍
        },
        // 规则对象(定义在data内的所有数据都可以直接使用,比如validator自定义校验函数)
        rules: {
          name: [{
              required: true,
              message: '部门名称不能为空',
              trigger: 'blur'
            },
            {
              min: 1,
              max: 50,
              message: '部门名称要求1-50个字符',
              trigger: 'blur'
            },
            {
              validator: validDepartmentName
            }
          ],
          code: [{
              required: true,
              message: '部门编码不能为空',
              trigger: 'blur'
            },
            {
              min: 1,
              max: 50,
              message: '部门编码要求1-50个字符',
              trigger: 'blur'
            },
            {
              validator: validCode,
              trigger: 'blur'
            }
          ],
          manager: [{
            required: true,
            message: '部门负责人不能为空',
            trigger: 'change'
          }],
          introduce: [{
              required: true,
              message: '部门介绍不能为空',
              trigger: 'blur'
            },
            {
              min: 1,
              max: 300,
              message: '部门介绍要求1-300个字符',
              trigger: 'blur'
            }
          ]
        }
      }
    },
    created() {},
    mounted() {},
    methods: {
      // 弹出层取消按钮
      cancelFN() {
        // 使用 .sync 修饰符
        this.$emit('update:departmentDialog', false)
      },
      // 弹出层确认按钮
      confirmFN() {
        // 兜底,防止用户一上来就点击确定按钮，不走blur校验
        this.$refs.deptForm.validate(valid => {
          if(valid){
            // 使用 .sync 修饰符
            this.$emit('update:departmentDialog', false)
            // 派发任务给父组件,让父组件发起请求
            // 这里无需区分新增/编辑反正最后都会把当前form对象派发给父组件
            // 在父组件判断编辑/新增即可
            this.$emit('addOrUpdateDepartemtFn',this.form)
          }
        })

      },
      // dialog关闭时重置表单对象
      dialogCloseFn(){
          this.$refs.deptForm.resetFields()
      }
    },
    computed: {},
    components: {}
  }
</script>
<style lang="less" scope>

</style>
